'''
Author: 红色梧桐 940120450@qq.com
Date: 2024-09-03 21:45:59
LastEditors: 红色梧桐 940120450@qq.com
LastEditTime: 2024-09-05 19:54:41
FilePath: \myReader\applications\extends\wxUtils.py
Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
'''
from ctypes import windll
import os
import subprocess
import sys
import time
import traceback
from typing import Literal
import win32gui
import win32con
import win32api
from wxauto import WeChat, uiautomation
from wxauto.elements import ContactWnd
from pywintypes import error as exeerror
from _ctypes import COMError

from applications.configs.common import WX_PATH

# 微信自定义异常
class WxError(Exception):
    code = 0
    message = ''

    def __init__(self, code, message) -> None:
        self.code = code
        self.message = message

wx_id = None
# 升级版微信客户端
class WeChatplus(WeChat):

    # 初始化函数
    def __init__(self, language: Literal['cn', 'cn_t', 'en'] = 'cn', debug: bool = False):
        # 调用继承类的初始化
        super().__init__(language=language, debug=debug)
        # 获取微信id
        self.wx_id = self.get_wx_id()

    # 跳转到第一位置
    def goto_chat_first(self):
        number = 100
        while True:
            self.SessionBox.ListControl().WheelUp(wheelTimes=8)
            # 查询第二个块是否为新的朋友
            new_fried = self.SessionBox.ListControl().GetChildren()[2].Name
            if new_fried == '新的朋友':
                break
            if number <= 0:
                break
            number -= 1
            
    # 重构切换到通讯录
    def SwitchToContact(self):
        """切换到通讯录页面"""
        self._show()
        self.A_ContactsIcon.Click(simulateMove=False)
        self.goto_chat_first()

    # 获取群聊列表
    def GetGroupList(self):
        self._show()
        self.SwitchToContact()
        self.SessionBox.ListControl(Name="联系人").ButtonControl(Name="通讯录管理").Click(simulateMove=False)
        contactwnd = ContactWnd()

        # 获取最后一个控件
        last_ele = contactwnd.Sidebar.GetChildren()[-1].GetChildren()[-1]
        if last_ele.Name == "最近群聊":
            last_ele.Click(simulateMove=False)

        group_ele = contactwnd.Sidebar.GetChildren()[-1].GetChildren()[-1]
        num = 10
        group_list = []
        has_name = set()
        while True:
            list_group = group_ele.ListControl().GetAllProgeny()[-1]
            group_name = {}
            for i in list_group:
                if '(' in i.Name:
                    group_name.update(num=int(str(i.Name).strip('(').strip(')')))
                    if group_name["name"] not in has_name:
                        group_list.append(group_name)
                        has_name.add(group_name["name"])
                else:
                    group_name = {"name": i.Name, "num": 0}
            group_ele.ListControl().WheelDown(wheelTimes=3)
            if num <= 0:
                break
            num -= 1
        del has_name
        contactwnd.Close()
        return group_list
    
    # 获取微信id
    def get_wx_id(self):
        global wx_id
        if not wx_id:
            try:
                self.A_MyIcon.Click()
                ContactProfileWnd = uiautomation.PaneControl(ClassName='ContactProfileWnd')
                wxid = ContactProfileWnd.GetAllProgeny()[-1][1]
                wx_id = wxid.Name
            except Exception:
                traceback.print_exc()
            finally:
                self.close_form()
            
        return wx_id
        
    # 获取最顶级窗口
    def close_form(self):
        uiautomation.SendKeys('{Esc}')

wx_client = None
not_Login = None   # 登录失败

# 微信控制工具类
class wxUtils():
    wx = None
    _name = None
    _login_hwnd = None

    # 初始化函数
    def __init__(self) -> None:
        self.wx_path = WX_PATH
        global wx_client
        try:
            if wx_client is None:
                self.get_wx_client()
        except Exception:
            traceback.format_exc()
            # 重新登录
            self.start_wx_serve()
    
    # 获取微信客户端
    def get_wx_client(self):
        global wx_client
        try:
            if wx_client is None:
                self.wx = WeChatplus(debug=False)
                wx_client = self.wx
        except COMError:
            traceback.print_exc()
            # 重启成功, 重启服务
            python = sys.executable
            os.execl(python, python, *sys.argv)

    # 微信点击登录
    def _wxlogin(self):
        # 查找微信登录窗口
        self._login_hwnd = win32gui.GetForegroundWindow()
        # 获取窗口的绝对位置
        left, top, right, bottom = win32gui.GetWindowRect(self._login_hwnd)
        # print(left, top, right, bottom)
        click_x = left + 100  # 替换为实际的相对X坐标
        click_y = top + 280   # 替换为实际的相对Y坐标
        # 移动鼠标到指定位置并点击
        win32api.SetCursorPos((click_x, click_y))
        # 模拟鼠标点击
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)
        # 点击成功，睡眠5秒
        time.sleep(5)
                
    # 开启微信服务
    def start_wx_serve(self, num=1):
        global wx_client, not_Login
        # 未登录失败, 并且微信客户端为空时调用
        if not_Login is None and wx_client is None:
            # 打开微信客户端
            subprocess.Popen(self.wx_path)
            time.sleep(2)
            # 登录第一次失败, 截图放到redis，远程登录。
            if num <= 0:
                # ImageGrab.grab().save("screenshot.png")
                # 关闭登录弹窗
                if self._login_hwnd:
                    not_Login = True
                    win32gui.PostMessage(self._login_hwnd, win32con.WM_CLOSE, 0, 0)
                return None
            self._wxlogin()
            # 再次获取微信客户端
            try:
                self.get_wx_client()
            except Exception:
                self.start_wx_serve(num - 1)

    # 解锁鼠标
    def unlock_mouse(self):
        windll.user32.BlockInput(False)
                
    # 调用微信方法
    def __getattr__(self, name):
        # 启用鼠标-键盘锁定
        windll.user32.BlockInput(True)
        try:
            # 检测微信客户端
            if self.wx is None:
                try:
                    self.get_wx_client()
                except:
                    raise WxError(500, '微信客户端未登录')
            
            # 运行函数
            method2 = getattr(self.wx, name, None)
            if callable(method2):
                # lambda 延迟操作，无法捕获异常，创建函数捕捉异常
                def get_args(that, *args, **kwargs):
                    global wx_client, not_Login
                    try:
                        result = method2(*args, **kwargs)
                        # 关闭-键盘锁定
                        windll.user32.BlockInput(False)
                        return result
                    except LookupError:
                        traceback.print_exc()
                        raise WxError(100, "操作失败，请稍后重试")
                    except exeerror:
                        wx_client = None
                        not_Login = None
                        that.wx = None
                        that._login_hwnd = None
                        raise WxError(500, "微信句柄丢失，请重新登录")
                    except Exception as e:
                        print(e, type(e))
                        raise WxError(500, str(e))
                    
                return lambda *args, **kwargs: get_args(self, *args, **kwargs)
            
        except WxError as e:
            raise e
        except Exception as e:
            raise WxError(500, str(e))

        raise WxError(401, f"没找到该函数：{name}")